﻿using Nop.Core.Domain.Blogs;
using Nop.Core.Domain.Directory;
using Nop.Core.Domain.Localization;
using Nop.Core.Domain.Messages;
using Nop.Services.Seo;
using Nop.Core.Domain.Seo;
using Nop.Core.Domain.Stores;
using Nop.Core.Infrastructure;
using Nop.Services.Localization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;

namespace Nop.Services.Installation
{
    public partial class CodeFirstInstallationService : IInstallationService
    {
        #region Fields
        private string InstallationDataFilePath = string.Empty;
        private XmlDocument InstallationDataXml = new XmlDocument();
        private XmlElement DataDocumentElement;
        #endregion

        void IInstallationService.InstallData(string defaultUserEmail, string defaultUserPassword, bool installSampleData)
        {
            this.InstallData(defaultUserEmail, defaultUserPassword, installSampleData);
            InstallationDataFilePath = _webHelper.MapPath("~/App_Data/Install/InstallationData.xml");
            InstallationDataXml.Load(InstallationDataFilePath);
            DataDocumentElement =  InstallationDataXml.DocumentElement;

            UpdateDefaultSite();
            InstallSites();
            //InstallMeasures();
            //InstallTaxCategories();
            InstallArabicLanguage();
            InstallArabicCurrencies();
            InstallOtherStates();
            //InstallShippingMethods();
            //InstallCustomersAndUsers(defaultUserEmail, defaultUserPassword);
            UpdateEmailAccount();
            //InstallMessageTemplates();
            //InstallTopics();
            //InstallSettings();
            InstallNopCmsLocaleResources();
            //InstallActivityLogTypes();
            //HashDefaultCustomerPassword(defaultUserEmail, defaultUserPassword);
            //InstallProductTemplates();
            //InstallCategoryTemplates();
            //InstallManufacturerTemplates();
            //InstallScheduleTasks();

            LocalizeCurrencies();
            LocalizeCountries();
            LocalizeStates();
            LocalizeShippingMethods();
            LocalizeMessageTemplates();
            LocalizeTopics();

            if (installSampleData)
            {
                LocalizeSpecificationAttributes();
                LocalizeProductAttributes();
                LocalizeCategories();
                LocalizeManufacturers();
                LocalizeProducts(defaultUserEmail);
                
                InstallArabicBlogPosts();
                InstallArabicNews();
                InstallArabicPolls();
                
                //InstallForums();
                //InstallDiscounts();
            }
        }

        private void UpdateDefaultSite()
        {
            Store DefaultSite = _storeRepository.Table.FirstOrDefault();
            if (DefaultSite != null) 
            {
                XmlNode DefaultSiteNode = DataDocumentElement.SelectSingleNode("DefaultSite");
                DefaultSite.Name = DefaultSiteNode.SelectSingleNode("Name").InnerText;
                DefaultSite.Url = DefaultSiteNode.SelectSingleNode("Url").InnerText;
                DefaultSite.Hosts = DefaultSiteNode.SelectSingleNode("Hosts").InnerText;
                _storeRepository.Update(DefaultSite);
            }
        }

        private void InstallSites()
        {
            var stores = new List<Store>();
            int result = 1;
            foreach (XmlNode site in DataDocumentElement.SelectNodes("Sites/Site"))
            {
                var s = new Store()
                {
                    Name = site.SelectSingleNode("Name").InnerText,
                    Url = site.SelectSingleNode("Url").InnerText,
                    SslEnabled = false,
                    Hosts = site.SelectSingleNode("Hosts").InnerText,
                    DisplayOrder = int.TryParse(site.SelectSingleNode("DisplayOrder").InnerText, out result) ? int.Parse(site.SelectSingleNode("DisplayOrder").InnerText) : result,
                };
                stores.Add(s);
            }
            stores.ForEach(x => _storeRepository.Insert(x));
        }

        private void InstallArabicLanguage()
        {
            var language = new Language
            {
                Name = "Arabic",
                LanguageCulture = "ar-SA",
                UniqueSeoCode = "ar",
                FlagImageFileName = "sa.png",
                Published = true,
                Rtl = true,
                DisplayOrder = 2
            };
            _languageRepository.Insert(language);
        }

        private void InstallArabicCurrencies()
        {
            var currencies = new List<Currency>();
            int DisplayOrder = 1;
            decimal Rate = 1;
            bool Published = true;
            foreach (XmlNode currency in DataDocumentElement.SelectNodes("Currencies/Currency"))
            {
                Currency c = new Currency();
                
                    c.Name = currency.SelectSingleNode("Name").InnerText;
                    c.CurrencyCode = currency.SelectSingleNode("CurrencyCode").InnerText;
                    c.DisplayLocale = currency.SelectSingleNode("DisplayLocale").InnerText;
                    c.CustomFormatting = currency.SelectSingleNode("CustomFormatting").InnerText;
                    c.Published = bool.TryParse(currency.SelectSingleNode("Published").InnerText, out Published) ? bool.Parse(currency.SelectSingleNode("Published").InnerText) : Published;
                    c.Rate = decimal.TryParse(currency.SelectSingleNode("Rate").InnerText, out Rate) ? decimal.Parse(currency.SelectSingleNode("Rate").InnerText) : Rate;
                    c.DisplayOrder = int.TryParse(currency.SelectSingleNode("DisplayOrder").InnerText, out DisplayOrder) ? int.Parse(currency.SelectSingleNode("DisplayOrder").InnerText) : DisplayOrder;
                    c.CreatedOnUtc = DateTime.UtcNow;
                    c.UpdatedOnUtc = DateTime.UtcNow;
           
                currencies.Add(c);
            }
            currencies.ForEach(x => _currencyRepository.Insert(x));
        }

        private void InstallOtherStates()
        {
            // throw new NotImplementedException();
        }

        private void UpdateEmailAccount()
        {
            int Port = 25;
            bool EnableSsl = false;
            bool UseDefaultCredentials = false;
            EmailAccount DefaultEmailAccount = _emailAccountRepository.Table.FirstOrDefault();
            if (DefaultEmailAccount != null)
            {
                XmlNode DefaultEmailAccountNode = DataDocumentElement.SelectSingleNode("DefaultEmailAccount");
                DefaultEmailAccount.Email = DefaultEmailAccountNode.SelectSingleNode("Email").InnerText;
                DefaultEmailAccount.DisplayName = DefaultEmailAccountNode.SelectSingleNode("DisplayName").InnerText;
                DefaultEmailAccount.Host = DefaultEmailAccountNode.SelectSingleNode("Host").InnerText;
                DefaultEmailAccount.Username = DefaultEmailAccountNode.SelectSingleNode("Username").InnerText;
                DefaultEmailAccount.Password = DefaultEmailAccountNode.SelectSingleNode("Password").InnerText;
                DefaultEmailAccount.Port = int.TryParse(DefaultEmailAccountNode.SelectSingleNode("Port").InnerText, out Port) ? int.Parse(DefaultEmailAccountNode.SelectSingleNode("Port").InnerText) : Port;
                DefaultEmailAccount.EnableSsl = bool.TryParse(DefaultEmailAccountNode.SelectSingleNode("EnableSsl").InnerText, out EnableSsl) ? bool.Parse(DefaultEmailAccountNode.SelectSingleNode("EnableSsl").InnerText) : EnableSsl;
                DefaultEmailAccount.UseDefaultCredentials = bool.TryParse(DefaultEmailAccountNode.SelectSingleNode("UseDefaultCredentials").InnerText, out UseDefaultCredentials) ? bool.Parse(DefaultEmailAccountNode.SelectSingleNode("UseDefaultCredentials").InnerText) : UseDefaultCredentials;
                _emailAccountRepository.Update(DefaultEmailAccount);
            }
        }

        private void InstallNopCmsLocaleResources()
        {
            var arLang = _languageRepository.Table.Single(l => l.Name == "Arabic");
            var enLang = _languageRepository.Table.Single(l => l.Name == "English");

            var arLanguage_packPath = _webHelper.MapPath("~/App_Data/Localization/language_pack_ar.xml");

            var nopcms_language_pack_enFilePath = _webHelper.MapPath("~/App_Data/Localization/nopcms_language_pack_en.xml");
            var nopcms_language_pack_arFilePath = _webHelper.MapPath("~/App_Data/Localization/nopcms_language_pack_ar.xml");


            InsertLocalResources(arLanguage_packPath, arLang);
            InsertLocalResources(nopcms_language_pack_enFilePath, enLang);
            InsertLocalResources(nopcms_language_pack_arFilePath, arLang);
        }

        private void InsertLocalResources(string filePath, Language lang)
        {
            #region Parse resource files (with <Children> elements)

            //read and parse original file with resources (with <Children> elements)
            var originalXmlDocument = new XmlDocument();
            originalXmlDocument.Load(filePath);

            var resources = new List<LocaleStringResourceParent>();

            foreach (XmlNode resNode in originalXmlDocument.SelectNodes(@"//Language/LocaleResource"))
                resources.Add(new LocaleStringResourceParent(resNode));

            resources.Sort((x1, x2) => x1.ResourceName.CompareTo(x2.ResourceName));

            foreach (var resource in resources)
                RecursivelySortChildrenResource(resource);

            var sb = new StringBuilder();
            var writer = XmlWriter.Create(sb);
            writer.WriteStartDocument();
            writer.WriteStartElement("Language", "");

            writer.WriteStartAttribute("Name", "");
            writer.WriteString(originalXmlDocument.SelectSingleNode(@"//Language").Attributes["Name"].InnerText.Trim());
            writer.WriteEndAttribute();

            foreach (var resource in resources)
                RecursivelyWriteResource(resource, writer);

            writer.WriteEndElement();
            writer.WriteEndDocument();
            writer.Flush();

            var parsedXml = sb.ToString();
            #endregion

            //now we have a parsed XML file (the same structure as exported language packs)
            //let's save resources
            var localizationService = EngineContext.Current.Resolve<ILocalizationService>();
            localizationService.ImportResourcesFromXml(lang, parsedXml);
        }

        private void LocalizeCurrencies()
        {
            // throw new NotImplementedException();
        }

        private void LocalizeCountries()
        {
            // throw new NotImplementedException();
        }

        private void LocalizeStates()
        {
            // throw new NotImplementedException();
        }

        private void LocalizeShippingMethods()
        {
            // throw new NotImplementedException();
        }

        private void LocalizeMessageTemplates()
        {
            // throw new NotImplementedException();
        }

        private void LocalizeTopics()
        {
            // throw new NotImplementedException();
        }

        private void LocalizeSpecificationAttributes()
        {
            //throw new NotImplementedException();
        }

        private void LocalizeProductAttributes()
        {
            //throw new NotImplementedException();
        }

        private void LocalizeCategories()
        {
            //throw new NotImplementedException();
        }

        private void LocalizeManufacturers()
        {
            //throw new NotImplementedException();
        }

        private void LocalizeProducts(string defaultUserEmail)
        {
            //throw new NotImplementedException();
        }

        private void InstallArabicBlogPosts()
        {
            var defaultLanguage = _languageRepository.Table.Single(l => l.Name == "Arabic");
            var blogPosts = new List<BlogPost>
                                {
                                    new BlogPost
                                        {
                                             AllowComments = true,
                                             Language = defaultLanguage,
                                             Title = "كيف تختار برنامج إدارة محتوى لموقعك",
                                             Body = "<p>أنظمة إدارة المحتوى Content management Systems CMS أصبحت من أهم البرامج المستخدمة من قبل أصحاب المواقع. وذلك لأنها تؤمن السرعة في العمل وانشاء الموقع فضلا على أنه يوجد الكثير من انظمة ادارة المحتوى مفتوحة المصدر. ولهذا السبب يجد العديد صعوبة في اختيار النظام المناسب لموقعهم.</p><br /><p><span style='font-size: large;'><strong>ما هو نظام ادارة المحتوى؟</strong></span></p><p>هو برنامج يستخدمه أصحاب المواقع ويكون متصل بقاعدة بيانات بحيث يستطيع المدير انشاء وتعديل وتحرير شكل المحتوى بطريقة ادارية مبسطة. ويتكون من نهايتين او واجهتين: واجة الادارة او لوحة التحكم Backend وفيها يتم التحرير والانشاء والتعديل والواجهة المعروضة Frontend وفيها يظهر الموقع بالشكل المطلوب.</p><p><strong><span style='font-size: large;'>لماذا يجب أن استخدم نظام ادارة محتوى لموقعي؟</span></strong></p><p>الجواب بسيط، وهو أن المواقع في العادة لا تقتصر على النصوص والصور والتي يمكنك انشاؤها باستخدام صفحات html بسيطة، ولكن ربما ستحتاج إلى نموذج مراسلة ومحتوى ديناميكي يمكّن الزوار من التفاعل مع الموقع.</p><p><strong><span style='font-size: large;'>أخطاء شائعة عند اختيار نظام ادارة المحتوى</span></strong></p><p><strong><span style='font-size: small;'>اختيار نظام ضخم ومشهور انه للمحترفين</span></strong></p><p>هذا الخطأ شائع بدرجة كبيرة وذلك أن المبتدئ خصوصا قد يقع فريسة لسمعة أحد البرامج لدى المحترفين ومطوري المواقع. وعند بدء العمل عليه يجد صعوبة في التعامل مع هذا البرنامج أو أنه يحتاج الى وقت وتعديل بدرجة تتعدى المعقول. لذلك تجد الذي يستخدم مثل هذه الأنظمة يستسلم بعد فترة ويقوم بتغيير البرنامج ان لم يغلق الموقع من الاساس.</p><p><strong><span style='font-size: small;'>النظام المدفوع أفضل من المفتوح المصدر</span></strong></p><p>في البداية يجب أن تعرف الفرق بين المجاني ومفتوح المصدر، اطلع على الملحق الثاني بهذا الموضوع: جملة: نظام إدارة المحتوى. النظام المدفوع قد يحقق بعض رغباتك الخاصة والمميزات أو العمليات التي تريد تنفيذها في موقعك ولكن ليس بالضرورة أن يكون أفضل من البرامج مفتوحة المصدر. بل ربما يكون مفتوح المصدر أفضل لكثرة الذين يعملون على تطويره.</p><p><strong><span style='font-size: small;'>الجري خلف السمعة دون التأكد من ملائمة النظام لموقعك</span></strong></p><p>هناك انظمة لها سمعة قياسية ومعروفة لدى الكثير سواءا كانوا مطورين او مستخدمين عاديين. هذه الأنظمة مهما زادت شهرتها لا يعني أنها الأفضل لموقعك، تأكد من مميزات البرنامج وملائمته لغرض موقعك قبل اختياره.</p><p><strong><span style='font-size: small;'>الطلب من احد الخبراء أن يختار لك نظام ادارة محتوى</span></strong></p><p>هذا قرار خاطئ بلا شك، فالخبير سيختار برنامج يسهل عليه التعامل معه ولكن ربما يكون الأمر مختلف بالنسبة لك، كما أن الخبير له نظرة مختلفة عن إنشاء المواقع وادارة محتواها. هذا لا يعني أن لا تستفيد من الخبراء، ولكن اطلب منهم النصيحة وأن يبينوا لك مميزات وعيوب كل نوع. وحاول ان تشرح للخبير الغرض من موقعك في البداية فهذا سيسهل عليه الأمر.</p><p><strong><span style='font-size: small;'>معايير اختيار نظام ادارة المحتوى</span></strong></p><p>هناك الكثير من المعايير ولكن ليس جميعها ينطبق على جميع المستخدمين أو جميع المواقع والأغراض التي صنعت من أجلها، لذلك سيتم ادراج بعض المعايير التي تهم المستخدمين بشكل عام.</p><p>سهولة وسرعة التنصيب.<br />وجود لوحة تحكم سهلة خالية من التعقيد.<br />امكانية زيادة فاعلية البرنامج لعمل وظائف أخرى، عند طريق الاضافات أو التعديل.<br />سهولة انشاء تصميم خارجي أو التعديل عليه.<br />وجود دعم كبير ومتعاون للنظام.<br />أن ترتاح للتعامل معه بغض النظر عن جميع النقاط السابقة.<br />إذا اجتمعت هذه المعايير في البرنامج الذي تبحث عنه فاعلم انك اقتربت من البرنامج المناسب لموقعك ولم يتبق إلا أن تتأكد أنه يقوم بجميع الوظائف التي تريد.</p>",
                                             Tags = "CMS, إدارة المحتوي, إدارة المواقع, التجارة الالكترونية, نظام إدارة الموقع, لغات البرمجة",
                                             CreatedOnUtc = DateTime.UtcNow,
                                        },
                                    new BlogPost
                                        {
                                             AllowComments = true,
                                             Language = defaultLanguage,
                                             Title = "خدمة العملاء",
                                             Body = "<p>إذا سئلت عن خدمة العملاء ما هي؟ فقد تتبادر إلى ذهنك أمور كثيرة، لكنك قد تختزل خدمة العملاء في بعض المظاهر المحددة، مثل أن تكون لدى العميل مشكلة وتساعده على حلها، أو لديه سؤال فتساعده على الإجابة عنه، وغيرها من الوظائف المشابهة التي تقوم بها أقسام خدمة العملاء في البقالات الكبيرة والمراكز التجارية وما إلى ذلك. ولكني أعتقد أن هذا النوع من الخدمة مقصور على فئة من العملاء، وهم العملاء الذين لديهم مشكلات تحتاج إلى تدخل لحلها. أما أكثر العملاء الذين لا تواجههم مشكلات كبيرة، أو واجهتهم مشكلات ولم يرغبوا (لسبب أو لآخر) في أن يخبروا الشركة بها، فلا تقدم لهم هذه الأقسام أي خدمة. و خدمة العملاء ذات مفهوم أشمل من مجرد حل المشكلات، كما لا ينبغي أن تنتظر إلى أن يبحث عنها العميل بنفسه، فهذا دور ناقص لأن الشركة تعتني فقط بالعملاء الذين لديهم مشكلات وتجشموا عناء طرحها على الشركة، أما غيرهم فلا. خاصة أننا نعلم أن عميلاً واحدًا من كل عشرة عملاء هو الذي يذهب ويطرح مشكلته على الشركة، ويطلب المساعدة في حلها. أما التسعة الباقون فلا يكلفون أنفسهم عناء مجرد إخبار الشركة، بل إنهم قد يذهبون ولا يعودون مرة أخرى، فتخسرهم الشركة بصمت، وقد يعطون انطباعًا سيئًا عن الشركة. فهل هذا هو الهدف الذي من أجله قمنا بتخصيص أقسام وتعيين موظفين للقيام بخدمة العملاء؟</p><p>لذلك أكرر وأقول إنه يجب ألا تكون خدمة العملاء مقتصرة على أشخاص معينين يقدمون الخدمة للعميل، بل يجب أن يشارك فيها كل موظف بدءًا من المدير العام وانتهاء بحارس الشركة. أما إذا لم تستشعر الشركة وكل شخص فيها هذه المسؤولية، فإن العملاء لن يجدوا من العناية ما يستحقونه، وقد يذهبون إلى شركات أخرى منافسة تعتني بهم بشكل أفضل. ويجب ألا يتعذر بعض الموظفين بأن ذلك ليس من عملهم ، بل إن خدمة العميل من واجب كل شخص بالشركة ، لذلك يجب أن تكون خدمة العملاء فلسفة وتوجهًا عامًا لدى الشركة ككل وليس مسؤولية أشخاص معينين وأقسام محددة، بل يجب أن تكون خدمة العملاء التزامًا دائمًا من كل العاملين بالشركة وفي كل الأوقات، فذلك هو الضمان الوحيد لمستقبل الشركة، وهو الوسيلة الوحيدة لتحقيق أهدافها.</p><p>ولا تكفي مئات الآلاف التي تصرف على الإعلانات،&nbsp; لأن دورها قد يقتصر على جذب العملاء إلى داخل المحل ويتوقف، ويلعب رجال البيع الدور الباقي من خلال تقديم خدمة عالية الجودة وإقناع العميل ليس بالشراء فقط، وإنما بتكرار الشراء مرات ومرات أخرى. فالتعامل مع العملاء بتقدير واحترام يعدّ كافيًا لجعلهم يرغبون في البقاء والتعامل معك.</p>",
                                             Tags = "العملاء, خدمة العملاء, الشركات, الإدارة, موظفين",
                                             CreatedOnUtc = DateTime.UtcNow.AddSeconds(1),
                                        },
                                };
            blogPosts.ForEach(bp => _blogPostRepository.Insert(bp));

            //search engine names
            foreach (var blogPost in blogPosts)
            {
                _urlRecordRepository.Insert(new UrlRecord()
                {
                    EntityId = blogPost.Id,
                    EntityName = "BlogPost",
                    LanguageId = blogPost.LanguageId,
                    IsActive = true,
                    Slug = blogPost.ValidateSeName("", blogPost.Title, true)
                });
            }
        }

        private void InstallArabicNews()
        {
            //throw new NotImplementedException();
        }

        private void InstallArabicPolls()
        {
            //throw new NotImplementedException();
        }

    }
}
